"""
汽车数据爬虫模块
用于爬取汽车之家网站的汽车排名数据
"""

import requests
import json
from typing import List, Dict, Optional
from dataclasses import dataclass


@dataclass
class CarInfo:
    """汽车信息数据类"""
    rank: int           # 排名
    name: str           # 车名
    score: float        # 评分
    price: str          # 价格
    sales: int          # 销量
    image_url: str      # 图片URL
    detail_url: str     # 详情页URL
    car_id: str         # 车辆ID


class CarCrawler:
    """汽车数据爬虫类"""
    
    def __init__(self):
        """初始化爬虫"""
        self.base_url = "https://car-web-api.autohome.com.cn/car/rank/getList"
        self.detail_base_url = "https://www.autohome.com.cn"
        self.headers = {
            'accept': 'application/json',
            'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6',
            'cache-control': 'no-cache',
            'origin': 'https://www.autohome.com.cn',
            'pragma': 'no-cache',
            'priority': 'u=1, i',
            'referer': 'https://www.autohome.com.cn/',
            'sec-ch-ua': '"Chromium";v="136", "Microsoft Edge";v="136", "Not.A/Brand";v="99"',
            'sec-ch-ua-mobile': '?0',
            'sec-ch-ua-platform': '"Windows"',
            'sec-fetch-dest': 'empty',
            'sec-fetch-mode': 'cors',
            'sec-fetch-site': 'same-site',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36 Edg/136.0.0.0',
        }
    
    def get_sedan_ranking(self, page_size: int = 50, page_index: int = 1, level_id: str = "1,2,3,4,5,6") -> List[CarInfo]:
        """
        获取轿车排名数据

        Args:
            page_size: 每页数据量，默认50
            page_index: 页码，默认1
            level_id: 轿车级别ID，默认全部轿车

        Returns:
            List[CarInfo]: 汽车信息列表
        """
        params = {
            'from': '28',
            'pm': '2',
            'pluginversion': '11.65.0',
            'model': '1',
            'channel': '0',
            'pageindex': str(page_index),
            'pagesize': str(page_size),
            'typeid': '1',           # 小轿车类型
            'subranktypeid': '1',
            'levelid': level_id,
            'price': '0-9000',
            'date': '2025-04',
        }
        
        try:
            response = requests.get(self.base_url, params=params, headers=self.headers, timeout=10)
            response.raise_for_status()
            data = response.json()
            
            if data.get('returncode') != 0:
                raise Exception(f"API返回错误: {data.get('message', '未知错误')}")
            
            car_list = data.get('result', {}).get('list', [])
            return self._parse_car_data(car_list)
            
        except requests.RequestException as e:
            raise Exception(f"网络请求失败: {str(e)}")
        except json.JSONDecodeError as e:
            raise Exception(f"JSON解析失败: {str(e)}")
        except Exception as e:
            raise Exception(f"数据获取失败: {str(e)}")
    
    def get_suv_ranking(self, page_size: int = 50, page_index: int = 1, level_id: str = "1,2,3,4,5") -> List[CarInfo]:
        """
        获取SUV排名数据

        Args:
            page_size: 每页数据量，默认50
            page_index: 页码，默认1
            level_id: SUV级别ID，默认全部SUV

        Returns:
            List[CarInfo]: 汽车信息列表
        """
        params = {
        'from': '28',
        'pm': '2',
        'pluginversion': '11.65.0',
        'model': '1',
        'channel': '0',
        'pageindex': str(page_index),
        'pagesize': str(page_size),
        'typeid': '1',
        'subranktypeid': '1',
        'levelid': level_id,
        'price': '0-9000',
        'date': '2025-04',
    }
        
        try:
            response = requests.get(self.base_url, params=params, headers=self.headers, timeout=10)
            response.raise_for_status()
            data = response.json()
            
            if data.get('returncode') != 0:
                raise Exception(f"API返回错误: {data.get('message', '未知错误')}")
            
            car_list = data.get('result', {}).get('list', [])
            return self._parse_car_data(car_list)
            
        except requests.RequestException as e:
            raise Exception(f"网络请求失败: {str(e)}")
        except json.JSONDecodeError as e:
            raise Exception(f"JSON解析失败: {str(e)}")
        except Exception as e:
            raise Exception(f"数据获取失败: {str(e)}")

    def get_mpv_ranking(self, page_size: int = 50, page_index: int = 1, level_id: str = "21,22,23,24") -> List[CarInfo]:
        """
        获取MPV排名数据

        Args:
            page_size: 每页数据量，默认50
            page_index: 页码，默认1
            level_id: MPV级别ID，默认全部MPV

        Returns:
            List[CarInfo]: 汽车信息列表
        """
        params = {
            'from': '28',
            'pm': '2',
            'pluginversion': '11.65.0',
            'model': '1',
            'channel': '0',
            'pageindex': str(page_index),
            'pagesize': str(page_size),
            'typeid': '1',           # MPV类型
            'subranktypeid': '1',
            'levelid': level_id,
            'price': '0-9000',
            'date': '2025-04',
        }

        try:
            response = requests.get(self.base_url, params=params, headers=self.headers, timeout=10)
            response.raise_for_status()
            data = response.json()

            if data.get('returncode') != 0:
                raise Exception(f"API返回错误: {data.get('message', '未知错误')}")

            car_list = data.get('result', {}).get('list', [])
            return self._parse_car_data(car_list)

        except requests.RequestException as e:
            raise Exception(f"网络请求失败: {str(e)}")
        except json.JSONDecodeError as e:
            raise Exception(f"JSON解析失败: {str(e)}")
        except Exception as e:
            raise Exception(f"数据获取失败: {str(e)}")

    def _parse_car_data(self, car_list: List[Dict]) -> List[CarInfo]:
        """
        解析汽车数据
        
        Args:
            car_list: 原始汽车数据列表
            
        Returns:
            List[CarInfo]: 解析后的汽车信息列表
        """
        cars = []
        for car_data in car_list:
            try:
                car_info = CarInfo(
                    rank=int(car_data.get('rank', 0)),
                    name=car_data.get('seriesname', '未知'),
                    score=float(car_data.get('scorevalue', 0.0)),
                    price=car_data.get('priceinfo', '暂无报价'),
                    sales=int(car_data.get('salecount', 0)),
                    image_url=car_data.get('seriesimage', ''),
                    car_id=str(car_data.get('seriesid', '')),
                    detail_url=f"{self.detail_base_url}/{car_data.get('seriesid', '')}/#pvareaid=6861512"
                )
                cars.append(car_info)
            except (ValueError, TypeError) as e:
                print(f"解析汽车数据时出错: {e}, 数据: {car_data}")
                continue
        
        return cars
    
    def get_car_types(self) -> Dict[str, str]:
        """
        获取支持的汽车类型

        Returns:
            Dict[str, str]: 汽车类型字典 {类型名: 类型ID}
        """
        return {
            "轿车": {
                "全部轿车": "1,2,3,4,5,6",
                "微型车": "1",
                "小型车": "2",
                "紧凑型车": "3",
                "中型车": "4",
                "中大型车": "5",
                "大型车": "6"
            },
            "SUV": {
                "全部SUV": "16,17,18,19,20",
                "小型SUV": "16",
                "紧凑型SUV": "17",
                "中型SUV": "18",
                "中大型SUV": "19",
                "大型SUV": "20"
            },
            "MPV": {
                "全部MPV": "21,22,23,24"
            }
        }


# 测试代码
if __name__ == "__main__":
    crawler = CarCrawler()
    try:
        print("正在获取小轿车排名数据...")
        cars = crawler.get_sedan_ranking(page_size=10)
        
        print(f"成功获取 {len(cars)} 条数据:")
        for car in cars[:5]:  # 只显示前5条
            print(f"排名: {car.rank}, 车名: {car.name}, 评分: {car.score}, "
                  f"价格: {car.price}, 销量: {car.sales}")
            
    except Exception as e:
        print(f"测试失败: {e}")
